
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import Dense, Dropout, Conv1D, MaxPooling1D, Flatten
from keras.models import load_model

import re


timestep = 30
# 数据集
# 输入数据15*20000
def get_supervised_data_X_Y(set_scaled, len):
    X = []
    y = []
    for i in range(timestep, len):
        X.append(set_scaled[:, i - timestep:i].T)
        y.append(set_scaled[:, i])
    X, y = np.array(X), np.array(y)
    # 将训练集变成3D，模型输入需要的形式
    # X = np.reshape(X, (X.shape[0], X.shape[1], X.shape[2], 1))
    # y = np.reshape(y, (y.shape[0], y.shape[1], 1))
    return X, y

def train(raw_data):
    print('train.....start')
    # 8000
    raw_data = raw_data[:, 0:8000]
    train_len = raw_data.shape[1]
    x_train, y_train = get_supervised_data_X_Y(raw_data, train_len)

    model = Sequential()
    model.add(Conv1D(filters=18, kernel_size=2, strides=1, padding='same', activation='relu',input_shape=(30, 15)))
    model.add(MaxPooling1D(pool_size=2, strides=2,padding='same'))
    model.add(Conv1D(filters=36, kernel_size=2, strides=1, padding='same', activation='relu',input_shape=(30, 15)))
    model.add(MaxPooling1D(pool_size=2, strides=2,padding='same'))
    model.add(Conv1D(filters=72,kernel_size=2,strides=1,padding='same', activation='relu',input_shape=(30, 15)))
    model.add(MaxPooling1D(pool_size=2, strides=2,padding='same'))
    model.add(Conv1D(filters=144,kernel_size=2,strides=1,padding='same', activation='relu',input_shape=(30, 15)))
    model.add(MaxPooling1D(pool_size=2, strides=2,padding='same'))
    model.add(Flatten())
    model.add(Dropout(0.5))
    model.add(Dense(output_dim=15, activation='tanh'))
    model.compile(optimizer='adam', loss='mean_squared_error')

    history = model.fit(x_train, y_train, epochs=100, batch_size=32, validation_split=0.05, verbose=2, shuffle=False)
    plt.plot(history.history['loss'], label='train')
    plt.plot(history.history['val_loss'], label='validation')
    plt.legend()
    plt.show()

    model.save('../CNN_model/model_cnn.h5')

    print('train.....end')


def test(raw_data):
    print('test...start')

    model = load_model('../CNN_model/model_cnn.h5')
    raw_data = raw_data[:, 10030:]
    test_len = raw_data.shape[1]
    x_test, y_test = get_supervised_data_X_Y(raw_data, test_len)

    predicted_value = model.predict(x_test)
    real_value = y_test

    error = np.abs(predicted_value - real_value) #

    error_mean = np.mean(error, axis=1)

    test_anomaly_score = []

    i = 0
    while i < len(error_mean):
        sum = 0
        s = i+10
        while i < s and i<len(error_mean):
            sum = sum + error_mean[i]
            i = i + 1
        test_anomaly_score.append(sum / 10)

    test_anomaly_score = np.array(test_anomaly_score)

    anomaly_pos = np.zeros(4)

    anomaly_span = [90]
    root_cause_f = open("../data/test_anomaly.csv", "r")
    row_index = 0

    for line in root_cause_f:
        line = line.strip()
        anomaly_axis = int(re.split(',', line)[0])
        anomaly_pos[row_index] = anomaly_axis / 10 - 1000 - anomaly_span[row_index % 1] / 10
        row_index += 1
    root_cause_f.close()

    fig, axes = plt.subplots()

    test_num = 1000
    plt.xticks(fontsize=25)

    plt.plot(test_anomaly_score, 'b', linewidth=2)
    threshold = np.full((test_num), 0.06)
    axes.plot(threshold, color='black', linestyle='--', linewidth=2)
    for k in range(len(anomaly_pos)):
        axes.axvspan(anomaly_pos[k], anomaly_pos[k] + anomaly_span[k % 1] / 10, color='red', linewidth=2)  # anomaly为起始位置，anomaly_pos[k]+anomaly_span[k%3]/gap_time为终止位置
        # axes.axvspan(anomaly_pos[k], anomaly_pos[k] + anomaly_span[k % 1], color='red', linewidth=2)
    plt.xlabel('Test Time', fontsize=25)
    plt.ylabel('Anomaly Score', fontsize=25)
    axes.spines['right'].set_visible(False)
    axes.spines['top'].set_visible(False)
    axes.yaxis.set_ticks_position('left')
    axes.xaxis.set_ticks_position('bottom')
    fig.subplots_adjust(bottom=0.25)
    fig.subplots_adjust(left=0.25)
    plt.title("CNN", size=25)
    plt.show()

    print('test...end')


if __name__ == '__main__':
    raw_data = pd.read_csv('../data/data_testAno.csv', header=None).values
    # min-max
    max_value = np.max(raw_data, axis=1)
    min_value = np.min(raw_data, axis=1)
    raw_data = (np.transpose(raw_data) - min_value) / (max_value - min_value + 1e-6)
    raw_data = np.transpose(raw_data)

    # train(raw_data)

    test(raw_data)


